<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="../Styles/sure3.css" rel="stylesheet" type="text/css"/>
    <link href="../Styles/base1.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<article class="markdown-body entry-content" itemprop="text">
    <h1><a href="#let-和-const-命令"  class="anchor" id="user-content-let-和-const-命令">
        
    </a>let 和 const 命令
    </h1>
    <h2><a href="#let-命令"  class="anchor" id="user-content-let-命令">
        
    </a>let 命令
    </h2>
    <h3><a href="#基本用法"  class="anchor" id="user-content-基本用法">
        
    </a>基本用法
    </h3>
    <p>ES6 新增了<code>let</code>命令，用来声明变量。它的用法类似于<code>var</code>，但是所声明的变量，只在<code>let</code>命令所在的代码块内有效。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-c1">10</span>;
  <span class="pl-k">var</span> b <span class="pl-k">=</span> <span class="pl-c1">1</span>;
}

a <span class="pl-c"><span class="pl-c">//</span> ReferenceError: a is not defined.</span>
b <span class="pl-c"><span class="pl-c">//</span> 1</span></pre>
    </div>
    <p>上面代码在代码块之中，分别用<code>let</code>和<code>var</code>声明了两个变量。然后在代码块之外调用这两个变量，结果<code>let</code>声明的变量报错，<code>var</code>声明的变量返回了正确的值。这表明，<code>let</code>声明的变量只在它所在的代码块有效。
    </p>
    <p><code>for</code>循环的计数器，就很合适使用<code>let</code>命令。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">for</span> (<span class="pl-k">let</span> i <span
            class="pl-k">=</span> <span class="pl-c1">0</span>; i <span class="pl-k">&lt;</span> <span
            class="pl-c1">10</span>; i<span class="pl-k">++</span>) {
  <span class="pl-c"><span class="pl-c">//</span> ...</span>
}

<span class="pl-en">console</span>.<span class="pl-c1">log</span>(i);
<span class="pl-c"><span class="pl-c">//</span> ReferenceError: i is not defined</span></pre>
    </div>
    <p>上面代码中，计数器<code>i</code>只在<code>for</code>循环体内有效，在循环体外引用就会报错。</p>
    <p>下面的代码如果使用<code>var</code>，最后输出的是<code>10</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> a <span class="pl-k">=</span> [];
<span class="pl-k">for</span> (<span class="pl-k">var</span> i <span class="pl-k">=</span> <span class="pl-c1">0</span>; i <span
                class="pl-k">&lt;</span> <span class="pl-c1">10</span>; i<span class="pl-k">++</span>) {
  a[i] <span class="pl-k">=</span> <span class="pl-k">function</span> () {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(i);
  };
}
a[<span class="pl-c1">6</span>](); <span class="pl-c"><span class="pl-c">//</span> 10</span></pre>
    </div>
    <p>上面代码中，变量<code>i</code>是<code>var</code>命令声明的，在全局范围内都有效，所以全局只有一个变量<code>i</code>。每一次循环，变量<code>i</code>的值都会发生改变，而循环内被赋给数组<code>a</code>的函数内部的<code>console.log(i)</code>，里面的<code>i</code>指向的就是全局的<code>i</code>。也就是说，所有数组<code>a</code>的成员里面的<code>i</code>，指向的都是同一个<code>i</code>，导致运行时输出的是最后一轮的<code>i</code>的值，也就是
        10。</p>
    <p>如果使用<code>let</code>，声明的变量仅在块级作用域内有效，最后输出的是 6。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> a <span class="pl-k">=</span> [];
<span class="pl-k">for</span> (<span class="pl-k">let</span> i <span class="pl-k">=</span> <span class="pl-c1">0</span>; i <span
                class="pl-k">&lt;</span> <span class="pl-c1">10</span>; i<span class="pl-k">++</span>) {
  a[i] <span class="pl-k">=</span> <span class="pl-k">function</span> () {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(i);
  };
}
a[<span class="pl-c1">6</span>](); <span class="pl-c"><span class="pl-c">//</span> 6</span></pre>
    </div>
    <p>
        上面代码中，变量<code>i</code>是<code>let</code>声明的，当前的<code>i</code>只在本轮循环有效，所以每一次循环的<code>i</code>其实都是一个新的变量，所以最后输出的是<code>6</code>。你可能会问，如果每一轮循环的变量<code>i</code>都是重新声明的，那它怎么知道上一轮循环的值，从而计算出本轮循环的值？这是因为
        JavaScript 引擎内部会记住上一轮循环的值，初始化本轮的变量<code>i</code>时，就在上一轮循环的基础上进行计算。</p>
    <p>另外，<code>for</code>循环还有一个特别之处，就是设置循环变量的那部分是一个父作用域，而循环体内部是一个单独的子作用域。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">for</span> (<span class="pl-k">let</span> i <span
            class="pl-k">=</span> <span class="pl-c1">0</span>; i <span class="pl-k">&lt;</span> <span
            class="pl-c1">3</span>; i<span class="pl-k">++</span>) {
  <span class="pl-k">let</span> i <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>abc<span
                class="pl-pds">'</span></span>;
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(i);
}
<span class="pl-c"><span class="pl-c">//</span> abc</span>
<span class="pl-c"><span class="pl-c">//</span> abc</span>
<span class="pl-c"><span class="pl-c">//</span> abc</span></pre>
    </div>
    <p>上面代码正确运行，输出了 3 次<code>abc</code>。这表明函数内部的变量<code>i</code>与循环变量<code>i</code>不在同一个作用域，有各自单独的作用域。</p>
    <h3><a href="#不存在变量提升"  class="anchor" id="user-content-不存在变量提升">
        
    </a>不存在变量提升
    </h3>
    <p><code>var</code>命令会发生”变量提升“现象，即变量可以在声明之前使用，值为<code>undefined</code>。这种现象多多少少是有些奇怪的，按照一般的逻辑，变量应该在声明语句之后才可以使用。</p>
    <p>为了纠正这种现象，<code>let</code>命令改变了语法行为，它所声明的变量一定要在声明后使用，否则报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> var 的情况</span>
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(foo); <span class="pl-c"><span class="pl-c">//</span> 输出undefined</span>
<span class="pl-k">var</span> foo <span class="pl-k">=</span> <span class="pl-c1">2</span>;

<span class="pl-c"><span class="pl-c">//</span> let 的情况</span>
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(bar); <span class="pl-c"><span class="pl-c">//</span> 报错ReferenceError</span>
<span class="pl-k">let</span> bar <span class="pl-k">=</span> <span class="pl-c1">2</span>;</pre>
    </div>
    <p>
        上面代码中，变量<code>foo</code>用<code>var</code>命令声明，会发生变量提升，即脚本开始运行时，变量<code>foo</code>已经存在了，但是没有值，所以会输出<code>undefined</code>。变量<code>bar</code>用<code>let</code>命令声明，不会发生变量提升。这表示在声明它之前，变量<code>bar</code>是不存在的，这时如果用到它，就会抛出一个错误。
    </p>
    <h3><a href="#暂时性死区"  class="anchor" id="user-content-暂时性死区">
        
    </a>暂时性死区
    </h3>
    <p>只要块级作用域内存在<code>let</code>命令，它所声明的变量就“绑定”（binding）这个区域，不再受外部的影响。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> tmp <span class="pl-k">=</span> <span
            class="pl-c1">123</span>;

<span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  tmp <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>abc<span
                class="pl-pds">'</span></span>; <span class="pl-c"><span class="pl-c">//</span> ReferenceError</span>
  <span class="pl-k">let</span> tmp;
}</pre>
    </div>
    <p>上面代码中，存在全局变量<code>tmp</code>，但是块级作用域内<code>let</code>又声明了一个局部变量<code>tmp</code>，导致后者绑定这个块级作用域，所以在<code>let</code>声明变量前，对<code>tmp</code>赋值会报错。
    </p>
    <p>ES6 明确规定，如果区块中存在<code>let</code>和<code>const</code>命令，这个区块对这些命令声明的变量，从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量，就会报错。</p>
    <p>总之，在代码块内，使用<code>let</code>命令声明变量之前，该变量都是不可用的。这在语法上，称为“暂时性死区”（temporal dead zone，简称 TDZ）。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  <span class="pl-c"><span class="pl-c">//</span> TDZ开始</span>
  tmp <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>abc<span
                class="pl-pds">'</span></span>; <span class="pl-c"><span class="pl-c">//</span> ReferenceError</span>
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(tmp); <span class="pl-c"><span
                class="pl-c">//</span> ReferenceError</span>

  <span class="pl-k">let</span> tmp; <span class="pl-c"><span class="pl-c">//</span> TDZ结束</span>
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(tmp); <span class="pl-c"><span
                class="pl-c">//</span> undefined</span>

  tmp <span class="pl-k">=</span> <span class="pl-c1">123</span>;
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(tmp); <span class="pl-c"><span
                class="pl-c">//</span> 123</span>
}</pre>
    </div>
    <p>上面代码中，在<code>let</code>命令声明变量<code>tmp</code>之前，都属于变量<code>tmp</code>的“死区”。</p>
    <p>“暂时性死区”也意味着<code>typeof</code>不再是一个百分之百安全的操作。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">typeof</span> x; <span class="pl-c"><span
            class="pl-c">//</span> ReferenceError</span>
<span class="pl-k">let</span> x;</pre>
    </div>
    <p>上面代码中，变量<code>x</code>使用<code>let</code>命令声明，所以在声明之前，都属于<code>x</code>的“死区”，只要用到该变量就会报错。因此，<code>typeof</code>运行时就会抛出一个<code>ReferenceError</code>。
    </p>
    <p>作为比较，如果一个变量根本没有被声明，使用<code>typeof</code>反而不会报错。</p>
    <div class="highlight highlight-source-js">
        <pre><span class="pl-k">typeof</span> undeclared_variable <span class="pl-c"><span class="pl-c">//</span> "undefined"</span></pre>
    </div>
    <p>上面代码中，<code>undeclared_variable</code>是一个不存在的变量名，结果返回“undefined”。所以，在没有<code>let</code>之前，<code>typeof</code>运算符是百分之百安全的，永远不会报错。现在这一点不成立了。这样的设计是为了让大家养成良好的编程习惯，变量一定要在声明之后使用，否则就报错。
    </p>
    <p>有些“死区”比较隐蔽，不太容易发现。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span
            class="pl-en">bar</span>(<span class="pl-smi">x</span> <span class="pl-k">=</span> <span
            class="pl-smi">y</span>, <span class="pl-smi">y</span> <span class="pl-k">=</span> <span
            class="pl-c1">2</span>) {
  <span class="pl-k">return</span> [x, y];
}

<span class="pl-en">bar</span>(); <span class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <p>上面代码中，调用<code>bar</code>函数之所以报错（某些实现可能不报错），是因为参数<code>x</code>默认值等于另一个参数<code>y</code>，而此时<code>y</code>还没有声明，属于”死区“。如果<code>y</code>的默认值是<code>x</code>，就不会报错，因为此时<code>x</code>已经声明了。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span
            class="pl-en">bar</span>(<span class="pl-smi">x</span> <span class="pl-k">=</span> <span
            class="pl-c1">2</span>, <span class="pl-smi">y</span> <span class="pl-k">=</span> <span
            class="pl-smi">x</span>) {
  <span class="pl-k">return</span> [x, y];
}
<span class="pl-en">bar</span>(); <span class="pl-c"><span class="pl-c">//</span> [2, 2]</span></pre>
    </div>
    <p>另外，下面的代码也会报错，与<code>var</code>的行为不同。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 不报错</span>
<span class="pl-k">var</span> x <span class="pl-k">=</span> x;

<span class="pl-c"><span class="pl-c">//</span> 报错</span>
<span class="pl-k">let</span> x <span class="pl-k">=</span> x;
<span class="pl-c"><span class="pl-c">//</span> ReferenceError: x is not defined</span></pre>
    </div>
    <p>
        上面代码报错，也是因为暂时性死区。使用<code>let</code>声明变量时，只要变量在还没有声明完成前使用，就会报错。上面这行就属于这个情况，在变量<code>x</code>的声明语句还没有执行完成前，就去取<code>x</code>的值，导致报错”x
        未定义“。</p>
    <p>ES6 规定暂时性死区和<code>let</code>、<code>const</code>语句不出现变量提升，主要是为了减少运行时错误，防止在变量声明前就使用这个变量，从而导致意料之外的行为。这样的错误在 ES5
        是很常见的，现在有了这种规定，避免此类错误就很容易了。</p>
    <p>总之，暂时性死区的本质就是，只要一进入当前作用域，所要使用的变量就已经存在了，但是不可获取，只有等到声明变量的那一行代码出现，才可以获取和使用该变量。</p>
    <h3><a href="#不允许重复声明"  class="anchor" id="user-content-不允许重复声明">
        
    </a>不允许重复声明
    </h3>
    <p><code>let</code>不允许在相同作用域内，重复声明同一个变量。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 报错</span>
<span class="pl-k">function</span> <span class="pl-en">func</span>() {
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-c1">10</span>;
  <span class="pl-k">var</span> a <span class="pl-k">=</span> <span class="pl-c1">1</span>;
}

<span class="pl-c"><span class="pl-c">//</span> 报错</span>
<span class="pl-k">function</span> <span class="pl-en">func</span>() {
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-c1">10</span>;
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-c1">1</span>;
}</pre>
    </div>
    <p>因此，不能在函数内部重新声明参数。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span
            class="pl-en">func</span>(<span class="pl-smi">arg</span>) {
  <span class="pl-k">let</span> arg; <span class="pl-c"><span class="pl-c">//</span> 报错</span>
}

<span class="pl-k">function</span> <span class="pl-en">func</span>(<span class="pl-smi">arg</span>) {
  {
    <span class="pl-k">let</span> arg; <span class="pl-c"><span class="pl-c">//</span> 不报错</span>
  }
}</pre>
    </div>
    <h2><a href="#块级作用域"  class="anchor" id="user-content-块级作用域">
        
    </a>块级作用域
    </h2>
    <h3><a href="#为什么需要块级作用域"  class="anchor" id="user-content-为什么需要块级作用域">
        
    </a>为什么需要块级作用域？
    </h3>
    <p>ES5 只有全局作用域和函数作用域，没有块级作用域，这带来很多不合理的场景。</p>
    <p>第一种场景，内层变量可能会覆盖外层变量。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> tmp <span class="pl-k">=</span> <span
            class="pl-k">new</span> <span class="pl-en">Date</span>();

<span class="pl-k">function</span> <span class="pl-en">f</span>() {
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(tmp);
  <span class="pl-k">if</span> (<span class="pl-c1">false</span>) {
    <span class="pl-k">var</span> tmp <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>hello world<span
                class="pl-pds">'</span></span>;
  }
}

<span class="pl-en">f</span>(); <span class="pl-c"><span class="pl-c">//</span> undefined</span></pre>
    </div>
    <p>
        上面代码的原意是，<code>if</code>代码块的外部使用外层的<code>tmp</code>变量，内部使用内层的<code>tmp</code>变量。但是，函数<code>f</code>执行后，输出结果为<code>undefined</code>，原因在于变量提升，导致内层的<code>tmp</code>变量覆盖了外层的<code>tmp</code>变量。
    </p>
    <p>第二种场景，用来计数的循环变量泄露为全局变量。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> s <span class="pl-k">=</span> <span
            class="pl-s"><span class="pl-pds">'</span>hello<span class="pl-pds">'</span></span>;

<span class="pl-k">for</span> (<span class="pl-k">var</span> i <span class="pl-k">=</span> <span class="pl-c1">0</span>; i <span
                class="pl-k">&lt;</span> <span class="pl-smi">s</span>.<span class="pl-c1">length</span>; i<span
                class="pl-k">++</span>) {
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(s[i]);
}

<span class="pl-en">console</span>.<span class="pl-c1">log</span>(i); <span class="pl-c"><span class="pl-c">//</span> 5</span></pre>
    </div>
    <p>上面代码中，变量<code>i</code>只用来控制循环，但是循环结束后，它并没有消失，泄露成了全局变量。</p>
    <h3><a href="#es6-的块级作用域"  class="anchor" id="user-content-es6-的块级作用域">
        
    </a>ES6 的块级作用域
    </h3>
    <p><code>let</code>实际上为 JavaScript 新增了块级作用域。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span class="pl-en">f1</span>() {
  <span class="pl-k">let</span> n <span class="pl-k">=</span> <span class="pl-c1">5</span>;
  <span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
    <span class="pl-k">let</span> n <span class="pl-k">=</span> <span class="pl-c1">10</span>;
  }
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(n); <span class="pl-c"><span class="pl-c">//</span> 5</span>
}</pre>
    </div>
    <p>上面的函数有两个代码块，都声明了变量<code>n</code>，运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用<code>var</code>定义变量<code>n</code>，最后输出的值才是
        10。</p>
    <p>ES6 允许块级作用域的任意嵌套。</p>
    <div class="highlight highlight-source-js">
        <pre>{{{{{<span class="pl-k">let</span> insane <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>Hello World<span class="pl-pds">'</span></span>}}}}};</pre>
    </div>
    <p>上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。</p>
    <div class="highlight highlight-source-js"><pre>{{{{
  {<span class="pl-k">let</span> insane <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World<span
                class="pl-pds">'</span></span>}
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(insane); <span class="pl-c"><span
                class="pl-c">//</span> 报错</span>
}}}};</pre>
    </div>
    <p>内层作用域可以定义外层作用域的同名变量。</p>
    <div class="highlight highlight-source-js"><pre>{{{{
  <span class="pl-k">let</span> insane <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World<span
                class="pl-pds">'</span></span>;
  {<span class="pl-k">let</span> insane <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World<span
                class="pl-pds">'</span></span>}
}}}};</pre>
    </div>
    <p>块级作用域的出现，实际上使得获得广泛应用的立即执行函数表达式（IIFE）不再必要了。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> IIFE 写法</span>
(<span class="pl-k">function</span> () {
  <span class="pl-k">var</span> tmp <span class="pl-k">=</span> <span class="pl-k">...</span>;
  <span class="pl-k">...</span>
}());

<span class="pl-c"><span class="pl-c">//</span> 块级作用域写法</span>
{
  <span class="pl-k">let</span> tmp <span class="pl-k">=</span> <span class="pl-k">...</span>;
  <span class="pl-k">...</span>
}</pre>
    </div>
    <h3><a href="#块级作用域与函数声明"  class="anchor" id="user-content-块级作用域与函数声明">
        
    </a>块级作用域与函数声明
    </h3>
    <p>函数能不能在块级作用域之中声明？这是一个相当令人混淆的问题。</p>
    <p>ES5 规定，函数只能在顶层作用域和函数作用域之中声明，不能在块级作用域声明。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 情况一</span>
<span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  <span class="pl-k">function</span> <span class="pl-en">f</span>() {}
}

<span class="pl-c"><span class="pl-c">//</span> 情况二</span>
<span class="pl-k">try</span> {
  <span class="pl-k">function</span> <span class="pl-en">f</span>() {}
} <span class="pl-k">catch</span>(e) {
  <span class="pl-c"><span class="pl-c">//</span> ...</span>
}</pre>
    </div>
    <p>上面两种函数声明，根据 ES5 的规定都是非法的。</p>
    <p>但是，浏览器没有遵守这个规定，为了兼容以前的旧代码，还是支持在块级作用域之中声明函数，因此上面两种情况实际都能运行，不会报错。</p>
    <p>ES6 引入了块级作用域，明确允许在块级作用域之中声明函数。ES6 规定，块级作用域之中，函数声明语句的行为类似于<code>let</code>，在块级作用域之外不可引用。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span class="pl-en">f</span>() { <span
            class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am outside!<span
            class="pl-pds">'</span></span>); }

(<span class="pl-k">function</span> () {
  <span class="pl-k">if</span> (<span class="pl-c1">false</span>) {
    <span class="pl-c"><span class="pl-c">//</span> 重复声明一次函数f</span>
    <span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am inside!<span
                class="pl-pds">'</span></span>); }
  }

  <span class="pl-en">f</span>();
}());</pre>
    </div>
    <p>上面代码在 ES5 中运行，会得到“I am inside!”，因为在<code>if</code>内声明的函数<code>f</code>会被提升到函数头部，实际运行的代码如下。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> ES5 环境</span>
<span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am outside!<span
                class="pl-pds">'</span></span>); }

(<span class="pl-k">function</span> () {
  <span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am inside!<span
                class="pl-pds">'</span></span>); }
  <span class="pl-k">if</span> (<span class="pl-c1">false</span>) {
  }
  <span class="pl-en">f</span>();
}());</pre>
    </div>
    <p>ES6 就完全不一样了，理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于<code>let</code>，对作用域之外没有影响。但是，如果你真的在 ES6
        浏览器中运行一下上面的代码，是会报错的，这是为什么呢？</p>
    <p>原来，如果改变了块级作用域内声明的函数的处理规则，显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题，ES6 在<a
            href="http://www.ecma-international.org/ecma-262/6.0/index.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics"
            rel="nofollow">附录 B</a>里面规定，浏览器的实现可以不遵守上面的规定，有自己的<a
            href="http://stackoverflow.com/questions/31419897/what-are-the-precise-semantics-of-block-level-functions-in-es6"
            rel="nofollow">行为方式</a>。</p>
    <ul>
        <li>允许在块级作用域内声明函数。</li>
        <li>函数声明类似于<code>var</code>，即会提升到全局作用域或函数作用域的头部。</li>
        <li>同时，函数声明还会提升到所在的块级作用域的头部。</li>
    </ul>
    <p>注意，上面三条规则只对 ES6 的浏览器实现有效，其他环境的实现不用遵守，还是将块级作用域的函数声明当作<code>let</code>处理。</p>
    <p>根据这三条规则，在浏览器的 ES6 环境中，块级作用域内声明的函数，行为类似于<code>var</code>声明的变量。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 浏览器的 ES6 环境</span>
<span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am outside!<span
                class="pl-pds">'</span></span>); }

(<span class="pl-k">function</span> () {
  <span class="pl-k">if</span> (<span class="pl-c1">false</span>) {
    <span class="pl-c"><span class="pl-c">//</span> 重复声明一次函数f</span>
    <span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am inside!<span
                class="pl-pds">'</span></span>); }
  }

  <span class="pl-en">f</span>();
}());
<span class="pl-c"><span class="pl-c">//</span> Uncaught TypeError: f is not a function</span></pre>
    </div>
    <p>上面的代码在符合 ES6 的浏览器中，都会报错，因为实际运行的是下面的代码。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 浏览器的 ES6 环境</span>
<span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am outside!<span
                class="pl-pds">'</span></span>); }
(<span class="pl-k">function</span> () {
  <span class="pl-k">var</span> f <span class="pl-k">=</span> <span class="pl-c1">undefined</span>;
  <span class="pl-k">if</span> (<span class="pl-c1">false</span>) {
    <span class="pl-k">function</span> <span class="pl-en">f</span>() { <span class="pl-en">console</span>.<span
                class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>I am inside!<span
                class="pl-pds">'</span></span>); }
  }

  <span class="pl-en">f</span>();
}());
<span class="pl-c"><span class="pl-c">//</span> Uncaught TypeError: f is not a function</span></pre>
    </div>
    <p>考虑到环境导致的行为差异太大，应该避免在块级作用域内声明函数。如果确实需要，也应该写成函数表达式，而不是函数声明语句。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 函数声明语句</span>
{
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>secret<span class="pl-pds">'</span></span>;
  <span class="pl-k">function</span> <span class="pl-en">f</span>() {
    <span class="pl-k">return</span> a;
  }
}

<span class="pl-c"><span class="pl-c">//</span> 函数表达式</span>
{
  <span class="pl-k">let</span> a <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>secret<span class="pl-pds">'</span></span>;
  <span class="pl-k">let</span> <span class="pl-en">f</span> <span class="pl-k">=</span> <span
                class="pl-k">function</span> () {
    <span class="pl-k">return</span> a;
  };
}</pre>
    </div>
    <p>另外，还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则，只在使用大括号的情况下成立，如果没有使用大括号，就会报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 不报错</span>
<span class="pl-s"><span class="pl-pds">'</span>use strict<span class="pl-pds">'</span></span>;
<span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  <span class="pl-k">function</span> <span class="pl-en">f</span>() {}
}

<span class="pl-c"><span class="pl-c">//</span> 报错</span>
<span class="pl-s"><span class="pl-pds">'</span>use strict<span class="pl-pds">'</span></span>;
<span class="pl-k">if</span> (<span class="pl-c1">true</span>)
  <span class="pl-k">function</span> <span class="pl-en">f</span>() {}</pre>
    </div>
    <h3><a href="#do-表达式"  class="anchor" id="user-content-do-表达式">
        
    </a>do 表达式
    </h3>
    <p>本质上，块级作用域是一个语句，将多个操作封装在一起，没有返回值。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-k">let</span> t <span class="pl-k">=</span> <span class="pl-en">f</span>();
  t <span class="pl-k">=</span> t <span class="pl-k">*</span> t <span class="pl-k">+</span> <span class="pl-c1">1</span>;
}</pre>
    </div>
    <p>上面代码中，块级作用域将两个语句封装在一起。但是，在块级作用域以外，没有办法得到<code>t</code>的值，因为块级作用域不返回值，除非<code>t</code>是全局变量。</p>
    <p>现在有一个<a href="http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions" rel="nofollow">提案</a>，使得块级作用域可以变为表达式，也就是说可以返回值，办法就是在块级作用域之前加上<code>do</code>，使它变为<code>do</code>表达式，然后就会返回内部最后执行的表达式的值。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">let</span> x <span class="pl-k">=</span> <span
            class="pl-k">do</span> {
  <span class="pl-k">let</span> t <span class="pl-k">=</span> <span class="pl-en">f</span>();
  t <span class="pl-k">*</span> t <span class="pl-k">+</span> <span class="pl-c1">1</span>;
};</pre>
    </div>
    <p>上面代码中，变量<code>x</code>会得到整个块级作用域的返回值（<code>t * t + 1</code>）。</p>
    <h2><a href="#const-命令"  class="anchor" id="user-content-const-命令">
        
    </a>const 命令
    </h2>
    <h3><a href="#基本用法-1"  class="anchor" id="user-content-基本用法-1">
        
    </a>基本用法
    </h3>
    <p><code>const</code>声明一个只读的常量。一旦声明，常量的值就不能改变。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">PI</span> <span
            class="pl-k">=</span> <span class="pl-c1">3.1415</span>;
<span class="pl-c1">PI</span> <span class="pl-c"><span class="pl-c">//</span> 3.1415</span>

<span class="pl-c1">PI</span> <span class="pl-k">=</span> <span class="pl-c1">3</span>;
<span class="pl-c"><span class="pl-c">//</span> TypeError: Assignment to constant variable.</span></pre>
    </div>
    <p>上面代码表明改变常量的值会报错。</p>
    <p><code>const</code>声明的变量不得改变值，这意味着，<code>const</code>一旦声明变量，就必须立即初始化，不能留到以后赋值。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">foo</span>;
<span class="pl-c"><span class="pl-c">//</span> SyntaxError: Missing initializer in const declaration</span></pre>
    </div>
    <p>上面代码表示，对于<code>const</code>来说，只声明不赋值，就会报错。</p>
    <p><code>const</code>的作用域与<code>let</code>命令相同：只在声明所在的块级作用域内有效。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  <span class="pl-k">const</span> <span class="pl-c1">MAX</span> <span class="pl-k">=</span> <span
                class="pl-c1">5</span>;
}

<span class="pl-c1">MAX</span> <span class="pl-c"><span class="pl-c">//</span> Uncaught ReferenceError: MAX is not defined</span></pre>
    </div>
    <p><code>const</code>命令声明的常量也是不提升，同样存在暂时性死区，只能在声明的位置后面使用。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">if</span> (<span class="pl-c1">true</span>) {
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-c1">MAX</span>); <span class="pl-c"><span
                class="pl-c">//</span> ReferenceError</span>
  <span class="pl-k">const</span> <span class="pl-c1">MAX</span> <span class="pl-k">=</span> <span
                class="pl-c1">5</span>;
}</pre>
    </div>
    <p>上面代码在常量<code>MAX</code>声明之前就调用，结果报错。</p>
    <p><code>const</code>声明的常量，也与<code>let</code>一样不可重复声明。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> message <span
            class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>Hello!<span
            class="pl-pds">"</span></span>;
<span class="pl-k">let</span> age <span class="pl-k">=</span> <span class="pl-c1">25</span>;

<span class="pl-c"><span class="pl-c">//</span> 以下两行都会报错</span>
<span class="pl-k">const</span> <span class="pl-c1">message</span> <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">"</span>Goodbye!<span class="pl-pds">"</span></span>;
<span class="pl-k">const</span> <span class="pl-c1">age</span> <span class="pl-k">=</span> <span class="pl-c1">30</span>;</pre>
    </div>
    <h3><a href="#本质"  class="anchor" id="user-content-本质">
        
    </a>本质
    </h3>
    <p><code>const</code>实际上保证的，并不是变量的值不得改动，而是变量指向的那个内存地址不得改动。对于简单类型的数据（数值、字符串、布尔值），值就保存在变量指向的那个内存地址，因此等同于常量。但对于复合类型的数据（主要是对象和数组），变量指向的内存地址，保存的只是一个指针，<code>const</code>只能保证这个指针是固定的，至于它指向的数据结构是不是可变的，就完全不能控制了。因此，将一个对象声明为常量必须非常小心。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">foo</span> <span
            class="pl-k">=</span> {};

<span class="pl-c"><span class="pl-c">//</span> 为 foo 添加一个属性，可以成功</span>
<span class="pl-smi">foo</span>.<span class="pl-smi">prop</span> <span class="pl-k">=</span> <span
                class="pl-c1">123</span>;
<span class="pl-smi">foo</span>.<span class="pl-smi">prop</span> <span class="pl-c"><span
                class="pl-c">//</span> 123</span>

<span class="pl-c"><span class="pl-c">//</span> 将 foo 指向另一个对象，就会报错</span>
foo <span class="pl-k">=</span> {}; <span class="pl-c"><span class="pl-c">//</span> TypeError: "foo" is read-only</span></pre>
    </div>
    <p>上面代码中，常量<code>foo</code>储存的是一个地址，这个地址指向一个对象。不可变的只是这个地址，即不能把<code>foo</code>指向另一个地址，但对象本身是可变的，所以依然可以为其添加新属性。</p>
    <p>下面是另一个例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">a</span> <span
            class="pl-k">=</span> [];
<span class="pl-smi">a</span>.<span class="pl-c1">push</span>(<span class="pl-s"><span class="pl-pds">'</span>Hello<span
                class="pl-pds">'</span></span>); <span class="pl-c"><span class="pl-c">//</span> 可执行</span>
<span class="pl-smi">a</span>.<span class="pl-c1">length</span> <span class="pl-k">=</span> <span class="pl-c1">0</span>;    <span
                class="pl-c"><span class="pl-c">//</span> 可执行</span>
a <span class="pl-k">=</span> [<span class="pl-s"><span class="pl-pds">'</span>Dave<span class="pl-pds">'</span></span>];    <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <p>上面代码中，常量<code>a</code>是一个数组，这个数组本身是可写的，但是如果将另一个数组赋值给<code>a</code>，就会报错。</p>
    <p>如果真的想将对象冻结，应该使用<code>Object.freeze</code>方法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">foo</span> <span
            class="pl-k">=</span> <span class="pl-c1">Object</span>.<span class="pl-en">freeze</span>({});

<span class="pl-c"><span class="pl-c">//</span> 常规模式时，下面一行不起作用；</span>
<span class="pl-c"><span class="pl-c">//</span> 严格模式时，该行会报错</span>
<span class="pl-smi">foo</span>.<span class="pl-smi">prop</span> <span class="pl-k">=</span> <span
                class="pl-c1">123</span>;</pre>
    </div>
    <p>上面代码中，常量<code>foo</code>指向一个冻结的对象，所以添加新属性不起作用，严格模式时还会报错。</p>
    <p>除了将对象本身冻结，对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> <span class="pl-en">constantize</span> <span
            class="pl-k">=</span> (<span class="pl-smi">obj</span>) <span class="pl-k">=&gt;</span> {
  <span class="pl-c1">Object</span>.<span class="pl-en">freeze</span>(obj);
  <span class="pl-c1">Object</span>.<span class="pl-c1">keys</span>(obj).<span class="pl-c1">forEach</span>( (<span
                class="pl-smi">key</span>, <span class="pl-smi">i</span>) <span class="pl-k">=&gt;</span> {
    <span class="pl-k">if</span> ( <span class="pl-k">typeof</span> obj[key] <span class="pl-k">===</span> <span
                class="pl-s"><span class="pl-pds">'</span>object<span class="pl-pds">'</span></span> ) {
      <span class="pl-en">constantize</span>( obj[key] );
    }
  });
};</pre>
    </div>
    <h3><a href="#es6-声明变量的六种方法"  class="anchor" id="user-content-es6-声明变量的六种方法">
        
    </a>ES6 声明变量的六种方法
    </h3>
    <p>ES5 只有两种声明变量的方法：<code>var</code>命令和<code>function</code>命令。ES6 除了添加<code>let</code>和<code>const</code>命令，后面章节还会提到，另外两种声明变量的方法：<code>import</code>命令和<code>class</code>命令。所以，ES6
        一共有 6 种声明变量的方法。</p>
    <h2><a href="#顶层对象的属性"  class="anchor" id="user-content-顶层对象的属性">
        
    </a>顶层对象的属性
    </h2>
    <p>顶层对象，在浏览器环境指的是<code>window</code>对象，在 Node 指的是<code>global</code>对象。ES5 之中，顶层对象的属性与全局变量是等价的。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">window</span>.<span
            class="pl-smi">a</span> <span class="pl-k">=</span> <span class="pl-c1">1</span>;
a <span class="pl-c"><span class="pl-c">//</span> 1</span>

a <span class="pl-k">=</span> <span class="pl-c1">2</span>;
<span class="pl-c1">window</span>.<span class="pl-smi">a</span> <span class="pl-c"><span class="pl-c">//</span> 2</span></pre>
    </div>
    <p>上面代码中，顶层对象的属性赋值与全局变量的赋值，是同一件事。</p>
    <p>顶层对象的属性与全局变量挂钩，被认为是 JavaScript
        语言最大的设计败笔之一。这样的设计带来了几个很大的问题，首先是没法在编译时就报出变量未声明的错误，只有运行时才能知道（因为全局变量可能是顶层对象的属性创造的，而属性的创造是动态的）；其次，程序员很容易不知不觉地就创建了全局变量（比如打字出错）；最后，顶层对象的属性是到处可以读写的，这非常不利于模块化编程。另一方面，<code>window</code>对象有实体含义，指的是浏览器的窗口对象，顶层对象是一个有实体含义的对象，也是不合适的。
    </p>
    <p>ES6 为了改变这一点，一方面规定，为了保持兼容性，<code>var</code>命令和<code>function</code>命令声明的全局变量，依旧是顶层对象的属性；另一方面规定，<code>let</code>命令、<code>const</code>命令、<code>class</code>命令声明的全局变量，不属于顶层对象的属性。也就是说，从
        ES6 开始，全局变量将逐步与顶层对象的属性脱钩。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> a <span class="pl-k">=</span> <span
            class="pl-c1">1</span>;
<span class="pl-c"><span class="pl-c">//</span> 如果在 Node 的 REPL 环境，可以写成 global.a</span>
<span class="pl-c"><span class="pl-c">//</span> 或者采用通用方法，写成 this.a</span>
<span class="pl-c1">window</span>.<span class="pl-smi">a</span> <span class="pl-c"><span class="pl-c">//</span> 1</span>

<span class="pl-k">let</span> b <span class="pl-k">=</span> <span class="pl-c1">1</span>;
<span class="pl-c1">window</span>.<span class="pl-smi">b</span> <span class="pl-c"><span class="pl-c">//</span> undefined</span></pre>
    </div>
    <p>上面代码中，全局变量<code>a</code>由<code>var</code>命令声明，所以它是顶层对象的属性；全局变量<code>b</code>由<code>let</code>命令声明，所以它不是顶层对象的属性，返回<code>undefined</code>。
    </p>
    <h2><a href="#global-对象"  class="anchor" id="user-content-global-对象">
        
    </a>global 对象
    </h2>
    <p>ES5 的顶层对象，本身也是一个问题，因为它在各种实现里面是不统一的。</p>
    <ul>
        <li>浏览器里面，顶层对象是<code>window</code>，但 Node 和 Web Worker 没有<code>window</code>。</li>
        <li>浏览器和 Web Worker 里面，<code>self</code>也指向顶层对象，但是 Node 没有<code>self</code>。</li>
        <li>Node 里面，顶层对象是<code>global</code>，但其他环境都不支持。</li>
    </ul>
    <p>同一段代码为了能够在各种环境，都能取到顶层对象，现在一般是使用<code>this</code>变量，但是有局限性。</p>
    <ul>
        <li>全局环境中，<code>this</code>会返回顶层对象。但是，Node 模块和 ES6 模块中，<code>this</code>返回的是当前模块。</li>
        <li>
            函数里面的<code>this</code>，如果函数不是作为对象的方法运行，而是单纯作为函数运行，<code>this</code>会指向顶层对象。但是，严格模式下，这时<code>this</code>会返回<code>undefined</code>。
        </li>
        <li>不管是严格模式，还是普通模式，<code>new Function('return this')()</code>，总是会返回全局对象。但是，如果浏览器用了 CSP（Content Security
            Policy，内容安全政策），那么<code>eval</code>、<code>new Function</code>这些方法都可能无法使用。
        </li>
    </ul>
    <p>综上所述，很难找到一种方法，可以在所有情况下，都取到顶层对象。下面是两种勉强可以使用的方法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 方法一</span>
(<span class="pl-k">typeof</span> <span class="pl-c1">window</span> <span class="pl-k">!==</span> <span
                class="pl-s"><span class="pl-pds">'</span>undefined<span class="pl-pds">'</span></span>
   <span class="pl-k">?</span> <span class="pl-c1">window</span>
   <span class="pl-k">:</span> (<span class="pl-k">typeof</span> <span class="pl-c1">process</span> <span class="pl-k">===</span> <span
                class="pl-s"><span class="pl-pds">'</span>object<span class="pl-pds">'</span></span> <span class="pl-k">&amp;&amp;</span>
      <span class="pl-k">typeof</span> require <span class="pl-k">===</span> <span class="pl-s"><span
                class="pl-pds">'</span>function<span class="pl-pds">'</span></span> <span class="pl-k">&amp;&amp;</span>
      <span class="pl-k">typeof</span> <span class="pl-c1">global</span> <span class="pl-k">===</span> <span
                class="pl-s"><span class="pl-pds">'</span>object<span class="pl-pds">'</span></span>)
     <span class="pl-k">?</span> <span class="pl-c1">global</span>
     <span class="pl-k">:</span> <span class="pl-c1">this</span>);

<span class="pl-c"><span class="pl-c">//</span> 方法二</span>
<span class="pl-k">var</span> <span class="pl-en">getGlobal</span> <span class="pl-k">=</span> <span class="pl-k">function</span> () {
  <span class="pl-k">if</span> (<span class="pl-k">typeof</span> self <span class="pl-k">!==</span> <span
                class="pl-s"><span class="pl-pds">'</span>undefined<span class="pl-pds">'</span></span>) { <span
                class="pl-k">return</span> self; }
  <span class="pl-k">if</span> (<span class="pl-k">typeof</span> <span class="pl-c1">window</span> <span class="pl-k">!==</span> <span
                class="pl-s"><span class="pl-pds">'</span>undefined<span class="pl-pds">'</span></span>) { <span
                class="pl-k">return</span> <span class="pl-c1">window</span>; }
  <span class="pl-k">if</span> (<span class="pl-k">typeof</span> <span class="pl-c1">global</span> <span class="pl-k">!==</span> <span
                class="pl-s"><span class="pl-pds">'</span>undefined<span class="pl-pds">'</span></span>) { <span
                class="pl-k">return</span> <span class="pl-c1">global</span>; }
  <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-en">Error</span>(<span
                class="pl-s"><span class="pl-pds">'</span>unable to locate global object<span
                class="pl-pds">'</span></span>);
};</pre>
    </div>
    <p>现在有一个<a
            href="https://github.com/tc39/proposal-global">提案</a>，在语言标准的层面，引入<code>global</code>作为顶层对象。也就是说，在所有环境下，<code>global</code>都是存在的，都可以从它拿到顶层对象。
    </p>
    <p>垫片库<a
            href="https://github.com/ljharb/System.global"><code>system.global</code></a>模拟了这个提案，可以在所有环境拿到<code>global</code>。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> CommonJS 的写法</span>
<span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">'</span>system.global/shim<span
                class="pl-pds">'</span></span>)();

<span class="pl-c"><span class="pl-c">//</span> ES6 模块的写法</span>
<span class="pl-k">import</span> <span class="pl-smi">shim</span> <span class="pl-k">from</span> <span
                class="pl-s"><span class="pl-pds">'</span>system.global/shim<span class="pl-pds">'</span></span>; <span
                class="pl-en">shim</span>();</pre>
    </div>
    <p>上面代码可以保证各种环境里面，<code>global</code>对象都是存在的。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> CommonJS 的写法</span>
<span class="pl-k">var</span> <span class="pl-c1">global</span> <span class="pl-k">=</span> <span
                class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">'</span>system.global<span
                class="pl-pds">'</span></span>)();

<span class="pl-c"><span class="pl-c">//</span> ES6 模块的写法</span>
<span class="pl-k">import</span> <span class="pl-smi">getGlobal</span> <span class="pl-k">from</span> <span
                class="pl-s"><span class="pl-pds">'</span>system.global<span class="pl-pds">'</span></span>;
<span class="pl-k">const</span> <span class="pl-c1">global</span> <span class="pl-k">=</span> <span class="pl-en">getGlobal</span>();</pre>
    </div>
    <p>上面代码将顶层对象放入变量<code>global</code>。</p>
</article>

</body>
</html>
